/**
 * 
 */
package spl.manager;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Formatter;
import java.util.HashMap;

import spl.utils.GlobalLogger;

import com.google.common.net.HttpHeaders;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;

/**
 * @author avikam
 *
 */
public class HTTPResponse {
	
	public static final String SO_LONG_AND_THANKS_FOR_ALL_THE_FISH = "Good-bye!";
	private int httpResponseCode;
	HashMap<String, String> httpResponseHeaders;
	private String httpMessage;
	
	private DataInputStream inputStream;
	private int contentLength;
	
	HTTPResponse(int responseCode, String msg, String response){
		this.init(responseCode, msg, "text/html; charset=utf-8", response.length());
		
		this.inputStream = new DataInputStream(new ByteArrayInputStream(response.getBytes()));		
		this.httpResponseHeaders.put(HttpHeaders.CONTENT_LENGTH, Integer.toString(response.length()));
		
	}
	
	HTTPResponse(int responseCode, String msg){
		this.init(responseCode, msg, "text/html; charset=utf-8", 0);
		
		this.inputStream = null;
		this.httpResponseHeaders.put(HttpHeaders.CONTENT_LENGTH, "0");
		
	}
	
	HTTPResponse(int responseCode){
		this.init(responseCode, "", "text/html; charset=utf-8", 0);
		
		this.inputStream = null;
		this.httpResponseHeaders.put(HttpHeaders.CONTENT_LENGTH, "0");
		
	}
	
	HTTPResponse(int responseCode, InputStream response, int size, String type){
		this.init(responseCode, "OK", type, size);
		
		this.inputStream = new DataInputStream(response);
	}
	
	private void init(int responseCode, String msg, String type, int length) {
		this.httpResponseCode = responseCode;
		this.httpMessage = msg;
		
		this.contentLength = length;
		// Init headers
		this.httpResponseHeaders = new HashMap<String, String> ();		
		this.httpResponseHeaders.put(HttpHeaders.SERVER, WorkManager.getInetAddress());
		this.httpResponseHeaders.put(HttpHeaders.CONTENT_TYPE, type);
		this.httpResponseHeaders.put(HttpHeaders.CONTENT_LENGTH, Integer.toString(length));
		
	}
	
	/**
	 * Add costume header
	 * @param name header name
	 * @param val value of header
	 */
	public void putHeader(String name, String val) {
		this.httpResponseHeaders.put(name, val);
	}
	
	/**
	 * Process the response and echo it on the socket's output
	 * @param clientSocket is the client connection
	 */
	public void response(SocketStream clientSocket) {
		int mtu = clientSocket.getMTU();
		byte[] sendPacket = new byte[mtu];
		
        Formatter formatter = new Formatter();

        
		MapJoiner join = Joiner.on("\r\n").withKeyValueSeparator(": ");
        
        clientSocket.out.print(
        			formatter.format(
        				"HTTP/1.1 %d %s\r\n"+ // HTTP/1.1 [code] [message]
        				"%s\r\n\r\n",				// Headers + terminating new-line

        				this.httpResponseCode, this.httpMessage,
        				join.join(this.httpResponseHeaders)
    				)
			);
        
        clientSocket.out.flush();
        // Nothing to serve
        if (null == this.inputStream || 0 == this.contentLength)
        	return;
        
		try {
			int readyToSend = this.inputStream.read(sendPacket, 0, Math.min(mtu, this.contentLength)); 
			while (readyToSend > 0 & this.contentLength > 0) {
				clientSocket.outputStream.write(sendPacket, 0, readyToSend);
				this.contentLength -= readyToSend;
				
				readyToSend = this.inputStream.read(sendPacket, 0, Math.min(mtu, this.contentLength));
			} 

			clientSocket.out.flush();
		} catch (IOException e) {
			GlobalLogger.getLogger().severe("IO Error while writing response!");
			return;
		}
	}
	
	/**
	 * @return the response code
	 */
	public int getResponseCode() {
		return this.httpResponseCode;
	}

	/**
	 * @return http message used for the request
	 */
	public String getMessage() {
		return this.httpMessage;
	}
}
